#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>

static int major;
static struct class *led_class;


/* regesters */
static volatile unsigned int* SET_GPIO_OPEN;
static volatile unsigned int* SET_GDIR;
static volatile unsigned int* SET_GDR;

static ssize_t led_write(struct file *filp, const char __user *buf,
			 size_t count, loff_t *ppos)
{
	char val;
	int ret;
	/* copy from user: get date from app */
	ret = copy_from_user(&val, buf, 1);
	/* to set gpio register:out 1/0 */
	if(val)
	{
		/* set gpio to let led on */
		*SET_GDR &= ~(1<<3);
	}
	else
	{
		/* set gpio to let led off */
		*SET_GDR |= (1<<3);
	}
	return 1;
}

static int led_open(struct inode *inode, struct file *filp)
{
	/*enable gpio
	 *configure pin as gpio 
	 *configure gpio as output 
	 */
	 *SET_GPIO_OPEN &= ~0xf;
	 *SET_GPIO_OPEN |= 0x5;

	 *SET_GDIR |= (1<<3);
	return 0;
}


static struct file_operations led_fops = {
	.owner		= THIS_MODULE,
	.write		= led_write,
	.open		= led_open,
};

/* 入口函数 */
static int __init led_init(struct cphy * cphy)(void)
{
	printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	major = register_chrdev(0, "led_drv", &led_fops);

	/* ioremap */
	SET_GPIO_OPEN = ioremap(0x02290000 + 0x14, 4);
	SET_GDIR = ioremap(0x020AC004, 4);
	SET_GDR = ioremap(0x020AC000, 4);

	led_class = class_create(THIS_MODULE, "my_led");
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled"); /* dev/myled */
	
	return 0;
}

static void __exit led_exit(void)
{
	iounmap(SET_GPIO_OPEN);
	iounmap(SET_GDIR);
	iounmap(SET_GDR);
	device_destroy(led_class, MKDEV(major, 0));
	class_destroy(led_class);
	unregister_chrdev(major, "led_drv");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

